package com.qian.ddj.bill.alipay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qian.api.ddj.model.Business;
import com.qian.api.ddj.model.Spider;
import com.qian.api.ddj.model.StatusDict;
import com.qian.api.ddj.service.IBusinessService;
import com.qian.api.ddj.service.IOrderService;
import com.qian.api.ddj.service.IPhoneCheckCodeService;
import com.qian.api.ddj.service.ISpiderService;
import com.qian.api.ddj.util.YunbaUtils;
import com.yaowk.api.system.model.Menu;
import com.yaowk.api.system.service.IMenuService;
import com.yaowk.api.utils.HttpUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ObjectUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Data
@Slf4j
public class Bill implements Runnable {

    //    private static final String loginUrl = "https://auth.alipay.com/login/index.htm";
    private static final String checkSecurityUrl = "https://consumeprod.alipay.com/record/checkSecurity.htm";
    private static final String checkCodeV3Url = "http://alisec.alipay.com/checkcodev3.php";
    private static final String billUrl = "https://consumeprod.alipay.com/record/advanced.htm";
    private static final String billUrl2 = "https://consumeprod.alipay.com/record/standard.htm";
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm");

    public static final ExecutorService executorService = Executors.newCachedThreadPool();

    private IPhoneCheckCodeService phoneCheckCodeService;
    private IOrderService orderService;
    private ISpiderService spiderService;
    private IMenuService menuService;
    private IBusinessService businessService;
    private String account;
    private String password;
    private Integer businessId;
    private WebDriver webDriver;
    private YunbaUtils yunbaUtils;

    public Bill() {
        DesiredCapabilities desiredCapabilities = DesiredCapabilities.phantomjs();
//        desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_PAGE_SETTINGS_PREFIX + "userAgent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36");
//        desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_PAGE_CUSTOMHEADERS_PREFIX + "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36");
        desiredCapabilities.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, "/usr/bin/phantomjs");
        webDriver = new PhantomJSDriver(desiredCapabilities);
    }

    @Override
    public void run() {
        log.info(" *********************** run " + account);
        // 每30秒钟查询一次账单
        while (true) {
            try {
                bill();
            } catch (Exception e) {
                e.printStackTrace();
                try {
                    // 截屏
                    this.saveScreen("error" + account, webDriver);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            } finally {
                try {
                    Thread.sleep(30000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 账号登录
     *
     * @throws InterruptedException
     * @throws IOException
     */
    private void login(String url) throws InterruptedException, IOException {
        log.info(" *********************** login " + account);
        Business business = businessService.findById(businessId);
        business.setBackup4(StatusDict.CLOSE.toString());
        businessService.save(business);
        try {
            Menu menu = new Menu();
            menu.setUrl("/cashNotify");
            Byte type = 3;
            menu.setType(type);
            List<String> aliases = menuService.findAliases(menu);
            log.info(JSON.toJSONString(aliases));
            for (String alias : aliases) {
                yunbaUtils.publishAlias(business.getName() + "有新的二维码验证", alias);
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        while (true) {

            // 用户确认获取二维码
            business = businessService.findById(businessId);
            if (StatusDict.FAIL.toString().equals(business.getBackup4())) {
                webDriver.get(url);
                if (url.startsWith(checkSecurityUrl)) {
                    business.setBackup3(this.getCheckQrCode());
                    business.setBackup4(StatusDict.WAIT_PAY.toString());
                    businessService.save(business);
                } else {
                    WebElement tabs = webDriver.findElement(By.id("J-loginMethod-tabs"));
                    tabs = tabs.findElements(By.tagName("li")).get(0);
                    tabs.click();


                    business.setBackup3(this.getQrCode());
                    business.setBackup4(StatusDict.WAIT_PAY.toString());
                    businessService.save(business);
                }
            }

            if (StatusDict.SUCCESS.toString().equals(business.getBackup4())) {
                business.setBackup3("");
                business.setBackup4("");
                businessService.save(business);
                Thread.sleep(5000);
                break;
            }

            Thread.sleep(5000);
        }
    }

    private void bill() throws InterruptedException, ParseException, IOException {
        log.info(" *********************** bill " + account);
        webDriver.get(billUrl);
        this.saveScreen("bill" + account, webDriver);

        String url = webDriver.getCurrentUrl();
        log.info(" *********************** url " + url);

        if (!billUrl.equalsIgnoreCase(url) && !billUrl2.equalsIgnoreCase(url)) {
            // 滑动验证码
            if (url.startsWith(checkCodeV3Url)) {
                log.info(account + "滑动验证码");
                WebElement element = webDriver.findElement(By.id("nc_1_n1z"));
                Point location = element.getLocation();
                Actions actions = new Actions(webDriver);
                actions.dragAndDropBy(element, location.x + 300, location.y).perform();
            } else {
                login(url);
            }

            webDriver.get(billUrl);
            url = webDriver.getCurrentUrl();

            if (!billUrl.equalsIgnoreCase(url) && !billUrl2.equalsIgnoreCase(url)) {
                return;
            }
        }


        log.info(" *********************** bill success " + account);

        // 判断简单版还是高级版
        if (billUrl2.equalsIgnoreCase(url)) {
            List<WebElement> links = webDriver.findElements(By.xpath("//a[@seed='link-link']"));
            for (WebElement link : links) {
                if ("切换到高级版".equals(link.getText())) {
                    link.click();
                    break;
                }
            }
        }
        // 获取订单页面成功
        List<Spider> lists = new LinkedList<>();
        int i = 0;
        List<WebElement> nextPageElements = webDriver.findElements(By.className("page-next"));
        WebElement nextPageElement = null;
        if (!CollectionUtils.isEmpty(nextPageElements)) {
            nextPageElement = nextPageElements.get(0);
        }

        String balance = webDriver.findElement(By.id("main")).findElement(By.xpath("//em[@class='ft-green']")).findElement(By.tagName("strong")).getText();
        Business business = new Business();
        business.setId(businessId);
        business.setBackup5(balance);
        businessService.save(business);

        // 查询数据库最新账单
        Spider spider = spiderService.findFirstByBusinessId(businessId);

        int index = 0;
        boolean pass = false;

        P1:
        while (true) {
            // 获取本页所有账单
            List<WebElement> bills = webDriver.findElements(By.className("J-item"));
            for (WebElement webElement : bills) {
                String hour = webElement.findElements(By.className("time-h")).get(i).getText();
                String time = webElement.findElements(By.className("time-d")).get(i).getText();
                String remark = webElement.findElements(By.className("consume-title")).get(i).getText();
                String orderInfo = webElement.findElements(By.className("tradeNo")).get(i).getText();
                String name = webElement.findElements(By.className("other")).get(i).getText();
                String amount = webElement.findElements(By.className("amount-pay")).get(i).getText();
                String status = webElement.findElements(By.className("status")).get(i).getText();

                if (!ObjectUtils.isEmpty(spider) && spider.getRemark().equalsIgnoreCase(remark)) {
                    pass = true;
                }

                if (pass) {
                    if (index >= 10)
                        break P1;
                    else {
                        index++;
                    }
                }

                Date payDate = dateFormat.parse(time + " " + hour);
                Spider spiderModel = new Spider();
                spiderModel.setPayDate(payDate);
                spiderModel.setRemark(remark);
                spiderModel.setName(name);
                spiderModel.setOrderInfo(orderInfo);
                spiderModel.setStatus(status);
                spiderModel.setAmount(amount);
                spiderModel.setBusinessId(businessId);
                lists.add(0, spiderModel);

                log.info(" *********************** bill one " + account);
            }

            if (!ObjectUtils.isEmpty(nextPageElement)) {
                log.info(" *********************** bill nextPage " + account);
                saveScreen("nextPage", webDriver);
                nextPageElement.click();
                Thread.sleep(2000);
            } else {
                break;
            }
        }

        spiderService.simpleSave(lists.get(lists.size() - 1));

        Notify notify = new Notify();
        notify.setSpiders(lists);
        notify.setOrderService(orderService);

        executorService.execute(notify);
    }

    /**
     * @param webElement
     * @param value
     * @throws InterruptedException
     */
    private void waitInput(WebElement webElement, String value) throws InterruptedException {
        for (int i = 0; i < value.length(); i++) {
            webElement.sendKeys(String.valueOf(value.charAt(i)));
            Thread.sleep(300);
        }
    }

    /**
     * 解析验证码
     *
     * @return
     * @throws IOException
     */
    private String getCode() throws IOException {
        WebElement codeImageElement = webDriver.findElement(By.id("J-checkcode-img"));
        File in = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        BufferedImage fullImage = ImageIO.read(in);
        // 获取验证码坐标，宽高
        Point point = codeImageElement.getLocation();
        int width = codeImageElement.getSize().getWidth();
        int height = codeImageElement.getSize().getHeight();

        BufferedImage codeImageBuffer = fullImage.getSubimage(point.getX(), point.getY(), width, height);
        ImageIO.write(codeImageBuffer, "png", in);
        FileCopyUtils.copy(in, new File("/billImage/" + account + ".png"));

        FileInputStream fileInputStream = new FileInputStream(in);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        String body = Base64Utils.encodeToString(bytes);
        fileInputStream.close();

        String result = HttpUtils.get("https://way.jd.com/showapi/checkcode_ys?typeId=34&appkey=03aab0cda43764eac02f7ef1666b70e4&body=img_base64=" + URLEncoder.encode(body));
        JSONObject jsonObject = JSON.parseObject(result);

        if ("10000".equalsIgnoreCase(jsonObject.getString("code"))) {
            String code = jsonObject.getJSONObject("result").getJSONObject("showapi_res_body").getString("Result");
            return code;
        }

        return null;
    }

    private void saveScreen(String fileName, WebDriver webDriver) throws IOException {
        File in = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        File out = new File("/billImage/" + fileName + ".jpg");
        FileCopyUtils.copy(in, out);
    }

    private String getQrCode() throws IOException {
        WebElement codeImageElement = webDriver.findElement(By.id("J-qrcode-body"));
        File in = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        BufferedImage fullImage = ImageIO.read(in);
        // 获取验证码坐标，宽高
        Point point = codeImageElement.getLocation();
        int width = codeImageElement.getSize().getWidth();
        int height = codeImageElement.getSize().getHeight();

        BufferedImage codeImageBuffer = fullImage.getSubimage(point.getX(), point.getY(), width, height);
        ImageIO.write(codeImageBuffer, "png", in);
        FileCopyUtils.copy(in, new File("/billImage/qrCode" + account + ".png"));

        FileInputStream fileInputStream = new FileInputStream(in);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        String body = Base64Utils.encodeToString(bytes);
        return "data:image/png;base64," + body;
    }

    // risk_qrcode_cnt
    private String getCheckQrCode() throws IOException {
        WebElement codeImageElement = webDriver.findElement(By.id("main-containor"));
        File in = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        BufferedImage fullImage = ImageIO.read(in);
        // 获取验证码坐标，宽高
        Point point = codeImageElement.getLocation();
        int width = codeImageElement.getSize().getWidth();
        int height = codeImageElement.getSize().getHeight();

        BufferedImage codeImageBuffer = fullImage.getSubimage(point.getX(), point.getY(), width, height);
        ImageIO.write(codeImageBuffer, "png", in);
        FileCopyUtils.copy(in, new File("/billImage/qrCode" + account + ".png"));

        FileInputStream fileInputStream = new FileInputStream(in);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        String body = Base64Utils.encodeToString(bytes);
        return "data:image/png;base64," + body;
    }
}
